import os
import platform
import re
import sqlite3
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime
from socket import *

RSIZE = 1024
usr_pattern = re.compile("^[-_a-zA-Z0-9]{4,16}$")
p_pattern = re.compile("@ [-_a-zA-Z0-9]{4,16} ")


def clear():
    system = platform.system()
    if system == "Windows":
        os.system("cls")
    elif system == "Linux":
        os.system("clear")


def info_split(string):
    eles = string.split(" ")
    return eles[0], eles[1], " ".join(eles[2:])


class Chatter:

    # __slots__ = ('name', 'sex', 'ip', )
    def __init__(self):
        self._server_ip = "127.0.0.1"
        self._port = 12581
        self._client = None
        self._name = "None"

        self._db_info = ("record.db", "record")
        self._conn = self.init_record(*self._db_info)

        self._t_start = datetime.now()
        self.client()

    def client(self):
        status = "1"
        while True:
            clear()
            if status == '1':  # 修改个人信息
                print("欢迎来到<YJ>的聊天室!!!")
                self.update_info()
            elif status == '2':  # 加入聊天室
                print("欢迎来到<YJ>的聊天室!!!")
                self.main()
                clear()
                print("欢迎来到<YJ>的聊天室!!!")
            elif status == '0':  # 退出程序
                self._conn.close()
                self.exit()
                break
            else:
                print("无效指令！")
            print("\n[1]修改信息   [2]加入聊天室   [0]退出程序")
            status = input("What do u want?\n> ")

    def update_info(self):
        """
        update your self-info

        :return:
        """
        while True:
            print(f"The old name is <{self._name}>")
            print("用户名规则：4到16位， 字母数字下划线减号")
            name = input("Input your name: ")
            res = usr_pattern.match(name)
            if res is not None:
                self._name = res.group()
                break
            else:
                print("Invalid name!")
        print(f"Your name now is: <{self._name}>")

    def main(self):
        self.login()
        futures = []
        with ThreadPoolExecutor() as t_exec:
            futures.append(t_exec.submit(self.recv_mes))
            futures.append(t_exec.submit(self.sending))
            as_completed(futures)

    def login(self):
        """
        join in a chatting room
        :return:
        """
        self._client = socket(AF_INET, SOCK_STREAM)
        self._server_ip = input("Please input Server IP (Default: 127.0.0.1): ")
        self._port = int(input("Please input Server port (Default: 12581): "))
        self._client.connect((self._server_ip, self._port))
        self.send_mes(self._conn, self._name, '0', '1')
        return

    def recv_mes(self):
        e = 0
        sql_conn = sqlite3.connect(self._db_info[0])
        while True:
            data = self._client.recv(1024)
            if not data:
                e += 1
                if e > 1000:
                    break
                continue
            e = 0
            string = data.decode('utf-8')
            from_sb, private, tmsg = info_split(string)
            t, msg = tmsg[0:26], tmsg[27:]
            self.save_record(sql_conn, 0, from_sb, self._name, private, t, msg)
            print(f"\b\b\b\bTime: {t} ", end="")
            if private == "1":
                print(f"<{from_sb}>: (私密消息) {msg}\n>>> ", end="")
            elif private == '2':
                print(f"[系统提示] 正在退出聊天, 原因: {msg}\n>>> ", end="")
                break
            else:
                print(f"<{from_sb}>: {msg}\n>>> ", end="")
        sql_conn.close()
        self.logout()

    def send_mes(self, sql_conn, msg, to_sb, private):
        if msg:
            t = datetime.now()
            m = f"{to_sb} {private} {t} {msg}"
            self._client.send(m.encode("utf-8"))
            self.save_record(sql_conn, 1, self._name, to_sb, private, t, msg)

    def sending(self):
        f = 0
        sql_conn = sqlite3.connect(self._db_info[0])
        while True:
            time.sleep(0.1)
            string_ = input()
            if not string_:
                f += 1
                print(">>> ", end="")
                if f > 2:
                    break
                continue
            f = 0
            msg = string_
            to_sb = "0"
            private = "0"
            # 退出指令
            if string_[0:8] == "@00 exit":
                break
            sb = p_pattern.search(string_)
            # 非公共指令
            if sb is not None:
                # 私发指令
                sb_str = sb.group()
                to_sb = sb_str[2:-1]
                msg = string_.replace(sb_str, "", 1)
                private = "1"
            self.send_mes(sql_conn, msg, to_sb, private)
        sql_conn.close()
        self.logout()

    def init_record(self, database_name, table_name):
        conn = sqlite3.connect(database_name)
        cursor = conn.cursor()

        # 检查缓存表是否存在，不存在则创建
        cursor.execute(f"select count(*) from sqlite_master where type = 'table' and name = '{table_name}'")
        exist = cursor.fetchone()[0]
        if not exist:
            table_create = \
                f"""
                CREATE TABLE {table_name} (
                    kind SMALLINT NOT NULL,
                    from_sb VARCHAR(16) NOT NULL,
                    to_sb VARCHAR(16) NOT NULL,
                    private CHARACTER(1) NOT NULL,
                    datetime CHARACTER(26) NOT NULL,
                    msg VARCHAR NOT NULL,
                    PRIMARY KEY(kind, from_sb, to_sb, datetime))
                """
            cursor.execute(table_create)
        conn.commit()
        cursor.close()
        return conn

    def save_record(self, sql_conn, kind, from_sb, to_sb, private, t, msg):
        e = f"INSERT INTO {self._db_info[1]} VALUES ({kind}, '{from_sb}', '{to_sb}', '{private}', '{t}', '{msg}')"
        sql_conn.execute(e)
        sql_conn.commit()

    def logout(self):
        self.send_mes(self._conn, "EXIT", "0", "1")
        print("已退出聊天室")
        time.sleep(1)
        self._client.close()

    def exit(self):
        self._conn.close()
        print(f"程序退出，时长{datetime.now()-self._t_start}"[:-7])
        print("❤感谢您的使用，See u!")


if __name__ == '__main__':
    C = Chatter()
